{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "        <script type=\"text/javascript\">\n",
       "        window.PlotlyConfig = {MathJaxConfig: 'local'};\n",
       "        if (window.MathJax) {MathJax.Hub.Config({SVG: {font: \"STIX-Web\"}});}\n",
       "        if (typeof require !== 'undefined') {\n",
       "        require.undef(\"plotly\");\n",
       "        requirejs.config({\n",
       "            paths: {\n",
       "                'plotly': ['https://cdn.plot.ly/plotly-2.4.2.min']\n",
       "            }\n",
       "        });\n",
       "        require(['plotly'], function(Plotly) {\n",
       "            window._Plotly = Plotly;\n",
       "        });\n",
       "        }\n",
       "        </script>\n",
       "        "
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import keras\n",
    "from keras.layers import Conv2D, Conv3D, Flatten, Dense, Reshape, BatchNormalization\n",
    "from keras.layers import Dropout, Input\n",
    "from keras.models import Model\n",
    "from keras.optimizers import adam_v2\n",
    "from keras.callbacks import ModelCheckpoint\n",
    "from keras.utils import np_utils\n",
    "\n",
    "from sklearn.decomposition import PCA\n",
    "from sklearn.model_selection import train_test_split\n",
    "from sklearn.metrics import confusion_matrix, accuracy_score, classification_report, cohen_kappa_score\n",
    "\n",
    "from operator import truediv\n",
    "\n",
    "from plotly.offline import init_notebook_mode\n",
    "\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import scipy.io as sio\n",
    "import os\n",
    "import spectral\n",
    "\n",
    "init_notebook_mode(connected=True)\n",
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Data Loading"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "## GLOBAL VARIABLES\n",
    "dataset = 'IP'\n",
    "test_ratio = 0.7\n",
    "windowSize = 25"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "def loadData(name):\n",
    "    data_path = os.path.join(os.getcwd(),'data')\n",
    "    if name == 'IP':\n",
    "        data = sio.loadmat(os.path.join(data_path, 'Indian_pines_corrected.mat'))['indian_pines_corrected']\n",
    "        labels = sio.loadmat(os.path.join(data_path, 'Indian_pines_gt.mat'))['indian_pines_gt']\n",
    "    elif name == 'SA':\n",
    "        data = sio.loadmat(os.path.join(data_path, 'Salinas_corrected.mat'))['salinas_corrected']\n",
    "        labels = sio.loadmat(os.path.join(data_path, 'Salinas_gt.mat'))['salinas_gt']\n",
    "    elif name == 'PU':\n",
    "        data = sio.loadmat(os.path.join(data_path, 'PaviaU.mat'))['paviaU']\n",
    "        labels = sio.loadmat(os.path.join(data_path, 'PaviaU_gt.mat'))['paviaU_gt']\n",
    "    \n",
    "    return data, labels"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "def splitTrainTestSet(X, y, testRatio, randomState=345):\n",
    "    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=testRatio, random_state=randomState,\n",
    "                                                        stratify=y)\n",
    "    return X_train, X_test, y_train, y_test"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "def applyPCA(X, numComponents=75):\n",
    "    newX = np.reshape(X, (-1, X.shape[2]))\n",
    "    pca = PCA(n_components=numComponents, whiten=True)\n",
    "    newX = pca.fit_transform(newX)\n",
    "    newX = np.reshape(newX, (X.shape[0],X.shape[1], numComponents))\n",
    "    return newX, pca"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "def padWithZeros(X, margin=2):\n",
    "    newX = np.zeros((X.shape[0] + 2 * margin, X.shape[1] + 2* margin, X.shape[2]))\n",
    "    x_offset = margin\n",
    "    y_offset = margin\n",
    "    newX[x_offset:X.shape[0] + x_offset, y_offset:X.shape[1] + y_offset, :] = X\n",
    "    return newX"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "def createImageCubes(X, y, windowSize=5, removeZeroLabels = True):\n",
    "    margin = int((windowSize - 1) / 2)\n",
    "    zeroPaddedX = padWithZeros(X, margin=margin)\n",
    "    # split patches\n",
    "    patchesData = np.zeros((X.shape[0] * X.shape[1], windowSize, windowSize, X.shape[2]))\n",
    "    patchesLabels = np.zeros((X.shape[0] * X.shape[1]))\n",
    "    patchIndex = 0\n",
    "    for r in range(margin, zeroPaddedX.shape[0] - margin):\n",
    "        for c in range(margin, zeroPaddedX.shape[1] - margin):\n",
    "            patch = zeroPaddedX[r - margin:r + margin + 1, c - margin:c + margin + 1]   \n",
    "            patchesData[patchIndex, :, :, :] = patch\n",
    "            patchesLabels[patchIndex] = y[r-margin, c-margin]\n",
    "            patchIndex = patchIndex + 1\n",
    "    if removeZeroLabels:\n",
    "        patchesData = patchesData[patchesLabels>0,:,:,:]\n",
    "        patchesLabels = patchesLabels[patchesLabels>0]\n",
    "        patchesLabels -= 1\n",
    "    return patchesData, patchesLabels"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "((145, 145, 200), (145, 145))"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "X, y = loadData(dataset)\n",
    "\n",
    "X.shape, y.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "K = X.shape[2]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(145, 145, 30)"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "K = 30 if dataset == 'IP' else 15\n",
    "X,pca = applyPCA(X,numComponents=K)\n",
    "\n",
    "X.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "((10249, 25, 25, 30), (10249,))"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "X, y = createImageCubes(X, y, windowSize=windowSize)\n",
    "\n",
    "X.shape, y.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "((3074, 25, 25, 30), (7175, 25, 25, 30), (3074,), (7175,))"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Xtrain, Xtest, ytrain, ytest = splitTrainTestSet(X, y, test_ratio)\n",
    "\n",
    "Xtrain.shape, Xtest.shape, ytrain.shape, ytest.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Xtrain, Xvalid, ytrain, yvalid = splitTrainTestSet(Xtrain, ytrain, 0.3333)\n",
    "\n",
    "Xtrain.shape, Xvalid.shape, ytrain.shape, yvalid.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Model and Training"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(3074, 25, 25, 30, 1)"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Xtrain = Xtrain.reshape(-1, windowSize, windowSize, K, 1)\n",
    "Xtrain.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(3074, 16)"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ytrain = np_utils.to_categorical(ytrain)\n",
    "ytrain.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Xvalid = Xvalid.reshape(-1, windowSize, windowSize, K, 1)\n",
    "Xvalid.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "yvalid = np_utils.to_categorical(yvalid)\n",
    "yvalid.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "S = windowSize\n",
    "L = K\n",
    "output_units = 9 if (dataset == 'PU' or dataset == 'PC') else 16"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(None, 19, 19, 18, 32)\n"
     ]
    }
   ],
   "source": [
    "## input layer\n",
    "input_layer = Input((S, S, L, 1))\n",
    "\n",
    "## convolutional layers\n",
    "conv_layer1 = Conv3D(filters=8, kernel_size=(3, 3, 7), activation='relu')(input_layer)\n",
    "conv_layer2 = Conv3D(filters=16, kernel_size=(3, 3, 5), activation='relu')(conv_layer1)\n",
    "conv_layer3 = Conv3D(filters=32, kernel_size=(3, 3, 3), activation='relu')(conv_layer2)\n",
    "print(conv_layer3.shape)\n",
    "conv3d_shape = conv_layer3.shape\n",
    "conv_layer3 = Reshape((conv3d_shape[1], conv3d_shape[2], conv3d_shape[3]*conv3d_shape[4]))(conv_layer3)\n",
    "conv_layer4 = Conv2D(filters=64, kernel_size=(3,3), activation='relu')(conv_layer3)\n",
    "\n",
    "flatten_layer = Flatten()(conv_layer4)\n",
    "\n",
    "## fully connected layers\n",
    "dense_layer1 = Dense(units=256, activation='relu')(flatten_layer)\n",
    "dense_layer1 = Dropout(0.4)(dense_layer1)\n",
    "dense_layer2 = Dense(units=128, activation='relu')(dense_layer1)\n",
    "dense_layer2 = Dropout(0.4)(dense_layer2)\n",
    "output_layer = Dense(units=output_units, activation='softmax')(dense_layer2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [],
   "source": [
    "# define the model with input layer and output layer\n",
    "model = Model(inputs=input_layer, outputs=output_layer)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Model: \"model\"\n",
      "_________________________________________________________________\n",
      "Layer (type)                 Output Shape              Param #   \n",
      "=================================================================\n",
      "input_1 (InputLayer)         [(None, 25, 25, 30, 1)]   0         \n",
      "_________________________________________________________________\n",
      "conv3d (Conv3D)              (None, 23, 23, 24, 8)     512       \n",
      "_________________________________________________________________\n",
      "conv3d_1 (Conv3D)            (None, 21, 21, 20, 16)    5776      \n",
      "_________________________________________________________________\n",
      "conv3d_2 (Conv3D)            (None, 19, 19, 18, 32)    13856     \n",
      "_________________________________________________________________\n",
      "reshape (Reshape)            (None, 19, 19, 576)       0         \n",
      "_________________________________________________________________\n",
      "conv2d (Conv2D)              (None, 17, 17, 64)        331840    \n",
      "_________________________________________________________________\n",
      "flatten (Flatten)            (None, 18496)             0         \n",
      "_________________________________________________________________\n",
      "dense (Dense)                (None, 256)               4735232   \n",
      "_________________________________________________________________\n",
      "dropout (Dropout)            (None, 256)               0         \n",
      "_________________________________________________________________\n",
      "dense_1 (Dense)              (None, 128)               32896     \n",
      "_________________________________________________________________\n",
      "dropout_1 (Dropout)          (None, 128)               0         \n",
      "_________________________________________________________________\n",
      "dense_2 (Dense)              (None, 16)                2064      \n",
      "=================================================================\n",
      "Total params: 5,122,176\n",
      "Trainable params: 5,122,176\n",
      "Non-trainable params: 0\n",
      "_________________________________________________________________\n"
     ]
    }
   ],
   "source": [
    "model.summary()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [],
   "source": [
    "# compiling the model\n",
    "adam = adam_v2.Adam(learning_rate=0.001, decay=1e-06)\n",
    "model.compile(loss='categorical_crossentropy', optimizer=adam, metrics=['accuracy'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [],
   "source": [
    "# checkpoint\n",
    "filepath = \"best-model.hdf5\"\n",
    "checkpoint = ModelCheckpoint(filepath, monitor='accuracy', verbose=1, save_best_only=True, mode='max')\n",
    "callbacks_list = [checkpoint]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/100\n",
      "13/13 [==============================] - 7s 211ms/step - loss: 2.8020 - accuracy: 0.1275\n",
      "\n",
      "Epoch 00001: accuracy improved from -inf to 0.12752, saving model to best-model.hdf5\n",
      "Epoch 2/100\n",
      "13/13 [==============================] - 3s 198ms/step - loss: 2.4923 - accuracy: 0.2131\n",
      "\n",
      "Epoch 00002: accuracy improved from 0.12752 to 0.21308, saving model to best-model.hdf5\n",
      "Epoch 3/100\n",
      "13/13 [==============================] - 3s 199ms/step - loss: 2.3071 - accuracy: 0.2241\n",
      "\n",
      "Epoch 00003: accuracy improved from 0.21308 to 0.22414, saving model to best-model.hdf5\n",
      "Epoch 4/100\n",
      "13/13 [==============================] - 3s 198ms/step - loss: 2.0664 - accuracy: 0.3159\n",
      "\n",
      "Epoch 00004: accuracy improved from 0.22414 to 0.31588, saving model to best-model.hdf5\n",
      "Epoch 5/100\n",
      "13/13 [==============================] - 3s 200ms/step - loss: 1.7313 - accuracy: 0.4157\n",
      "\n",
      "Epoch 00005: accuracy improved from 0.31588 to 0.41574, saving model to best-model.hdf5\n",
      "Epoch 6/100\n",
      "13/13 [==============================] - 3s 200ms/step - loss: 1.4768 - accuracy: 0.4857\n",
      "\n",
      "Epoch 00006: accuracy improved from 0.41574 to 0.48569, saving model to best-model.hdf5\n",
      "Epoch 7/100\n",
      "13/13 [==============================] - 3s 200ms/step - loss: 1.1743 - accuracy: 0.6015\n",
      "\n",
      "Epoch 00007: accuracy improved from 0.48569 to 0.60150, saving model to best-model.hdf5\n",
      "Epoch 8/100\n",
      "13/13 [==============================] - 3s 200ms/step - loss: 0.8710 - accuracy: 0.7206\n",
      "\n",
      "Epoch 00008: accuracy improved from 0.60150 to 0.72056, saving model to best-model.hdf5\n",
      "Epoch 9/100\n",
      "13/13 [==============================] - 3s 200ms/step - loss: 0.6480 - accuracy: 0.7908\n",
      "\n",
      "Epoch 00009: accuracy improved from 0.72056 to 0.79083, saving model to best-model.hdf5\n",
      "Epoch 10/100\n",
      "13/13 [==============================] - 3s 200ms/step - loss: 0.5976 - accuracy: 0.8077\n",
      "\n",
      "Epoch 00010: accuracy improved from 0.79083 to 0.80774, saving model to best-model.hdf5\n",
      "Epoch 11/100\n",
      "13/13 [==============================] - 3s 200ms/step - loss: 0.4721 - accuracy: 0.8543\n",
      "\n",
      "Epoch 00011: accuracy improved from 0.80774 to 0.85426, saving model to best-model.hdf5\n",
      "Epoch 12/100\n",
      "13/13 [==============================] - 3s 200ms/step - loss: 0.6746 - accuracy: 0.8100\n",
      "\n",
      "Epoch 00012: accuracy did not improve from 0.85426\n",
      "Epoch 13/100\n",
      "13/13 [==============================] - 3s 200ms/step - loss: 0.4920 - accuracy: 0.8513\n",
      "\n",
      "Epoch 00013: accuracy did not improve from 0.85426\n",
      "Epoch 14/100\n",
      "13/13 [==============================] - 3s 200ms/step - loss: 0.3294 - accuracy: 0.8985\n",
      "\n",
      "Epoch 00014: accuracy improved from 0.85426 to 0.89850, saving model to best-model.hdf5\n",
      "Epoch 15/100\n",
      "13/13 [==============================] - 3s 199ms/step - loss: 0.2352 - accuracy: 0.9255\n",
      "\n",
      "Epoch 00015: accuracy improved from 0.89850 to 0.92550, saving model to best-model.hdf5\n",
      "Epoch 16/100\n",
      "13/13 [==============================] - 3s 200ms/step - loss: 0.1927 - accuracy: 0.9388\n",
      "\n",
      "Epoch 00016: accuracy improved from 0.92550 to 0.93884, saving model to best-model.hdf5\n",
      "Epoch 17/100\n",
      "13/13 [==============================] - 3s 200ms/step - loss: 0.1435 - accuracy: 0.9561\n",
      "\n",
      "Epoch 00017: accuracy improved from 0.93884 to 0.95608, saving model to best-model.hdf5\n",
      "Epoch 18/100\n",
      "13/13 [==============================] - 3s 200ms/step - loss: 0.1290 - accuracy: 0.9610\n",
      "\n",
      "Epoch 00018: accuracy improved from 0.95608 to 0.96096, saving model to best-model.hdf5\n",
      "Epoch 19/100\n",
      "13/13 [==============================] - 3s 200ms/step - loss: 0.1141 - accuracy: 0.9655\n",
      "\n",
      "Epoch 00019: accuracy improved from 0.96096 to 0.96552, saving model to best-model.hdf5\n",
      "Epoch 20/100\n",
      "13/13 [==============================] - 3s 201ms/step - loss: 0.0880 - accuracy: 0.9740\n",
      "\n",
      "Epoch 00020: accuracy improved from 0.96552 to 0.97398, saving model to best-model.hdf5\n",
      "Epoch 21/100\n",
      "13/13 [==============================] - 3s 201ms/step - loss: 0.0842 - accuracy: 0.9750\n",
      "\n",
      "Epoch 00021: accuracy improved from 0.97398 to 0.97495, saving model to best-model.hdf5\n",
      "Epoch 22/100\n",
      "13/13 [==============================] - 3s 201ms/step - loss: 0.0731 - accuracy: 0.9772\n",
      "\n",
      "Epoch 00022: accuracy improved from 0.97495 to 0.97723, saving model to best-model.hdf5\n",
      "Epoch 23/100\n",
      "13/13 [==============================] - 3s 202ms/step - loss: 0.2291 - accuracy: 0.9457\n",
      "\n",
      "Epoch 00023: accuracy did not improve from 0.97723\n",
      "Epoch 24/100\n",
      "13/13 [==============================] - 3s 203ms/step - loss: 0.1475 - accuracy: 0.9577\n",
      "\n",
      "Epoch 00024: accuracy did not improve from 0.97723\n",
      "Epoch 25/100\n",
      "13/13 [==============================] - 3s 200ms/step - loss: 0.1124 - accuracy: 0.9688\n",
      "\n",
      "Epoch 00025: accuracy did not improve from 0.97723\n",
      "Epoch 26/100\n",
      "13/13 [==============================] - 3s 200ms/step - loss: 0.0933 - accuracy: 0.9756\n",
      "\n",
      "Epoch 00026: accuracy did not improve from 0.97723\n",
      "Epoch 27/100\n",
      "13/13 [==============================] - 3s 201ms/step - loss: 0.0603 - accuracy: 0.9805\n",
      "\n",
      "Epoch 00027: accuracy improved from 0.97723 to 0.98048, saving model to best-model.hdf5\n",
      "Epoch 28/100\n",
      "13/13 [==============================] - 3s 201ms/step - loss: 0.0486 - accuracy: 0.9844\n",
      "\n",
      "Epoch 00028: accuracy improved from 0.98048 to 0.98439, saving model to best-model.hdf5\n",
      "Epoch 29/100\n",
      "13/13 [==============================] - 3s 201ms/step - loss: 0.0490 - accuracy: 0.9837\n",
      "\n",
      "Epoch 00029: accuracy did not improve from 0.98439\n",
      "Epoch 30/100\n",
      "13/13 [==============================] - 3s 200ms/step - loss: 0.0482 - accuracy: 0.9860\n",
      "\n",
      "Epoch 00030: accuracy improved from 0.98439 to 0.98601, saving model to best-model.hdf5\n",
      "Epoch 31/100\n",
      "13/13 [==============================] - 3s 200ms/step - loss: 0.0494 - accuracy: 0.9844\n",
      "\n",
      "Epoch 00031: accuracy did not improve from 0.98601\n",
      "Epoch 32/100\n",
      "13/13 [==============================] - 3s 201ms/step - loss: 0.0382 - accuracy: 0.9886\n",
      "\n",
      "Epoch 00032: accuracy improved from 0.98601 to 0.98861, saving model to best-model.hdf5\n",
      "Epoch 33/100\n",
      "13/13 [==============================] - 3s 201ms/step - loss: 0.0482 - accuracy: 0.9860\n",
      "\n",
      "Epoch 00033: accuracy did not improve from 0.98861\n",
      "Epoch 34/100\n",
      "13/13 [==============================] - 3s 201ms/step - loss: 0.0374 - accuracy: 0.9893\n",
      "\n",
      "Epoch 00034: accuracy improved from 0.98861 to 0.98926, saving model to best-model.hdf5\n",
      "Epoch 35/100\n",
      "13/13 [==============================] - 3s 201ms/step - loss: 0.0325 - accuracy: 0.9896\n",
      "\n",
      "Epoch 00035: accuracy improved from 0.98926 to 0.98959, saving model to best-model.hdf5\n",
      "Epoch 36/100\n",
      "13/13 [==============================] - 3s 202ms/step - loss: 0.0324 - accuracy: 0.9902\n",
      "\n",
      "Epoch 00036: accuracy improved from 0.98959 to 0.99024, saving model to best-model.hdf5\n",
      "Epoch 37/100\n",
      "13/13 [==============================] - 3s 202ms/step - loss: 0.0284 - accuracy: 0.9906\n",
      "\n",
      "Epoch 00037: accuracy improved from 0.99024 to 0.99057, saving model to best-model.hdf5\n",
      "Epoch 38/100\n",
      "13/13 [==============================] - 3s 218ms/step - loss: 0.0264 - accuracy: 0.9915\n",
      "\n",
      "Epoch 00038: accuracy improved from 0.99057 to 0.99154, saving model to best-model.hdf5\n",
      "Epoch 39/100\n",
      "13/13 [==============================] - 3s 206ms/step - loss: 0.0272 - accuracy: 0.9909\n",
      "\n",
      "Epoch 00039: accuracy did not improve from 0.99154\n",
      "Epoch 40/100\n",
      "13/13 [==============================] - 3s 201ms/step - loss: 0.0185 - accuracy: 0.9941\n",
      "\n",
      "Epoch 00040: accuracy improved from 0.99154 to 0.99414, saving model to best-model.hdf5\n",
      "Epoch 41/100\n",
      "13/13 [==============================] - 3s 201ms/step - loss: 0.0221 - accuracy: 0.9945\n",
      "\n",
      "Epoch 00041: accuracy improved from 0.99414 to 0.99447, saving model to best-model.hdf5\n",
      "Epoch 42/100\n",
      "13/13 [==============================] - 3s 201ms/step - loss: 0.0303 - accuracy: 0.9922\n",
      "\n",
      "Epoch 00042: accuracy did not improve from 0.99447\n",
      "Epoch 43/100\n",
      "13/13 [==============================] - 3s 201ms/step - loss: 0.0214 - accuracy: 0.9938\n",
      "\n",
      "Epoch 00043: accuracy did not improve from 0.99447\n",
      "Epoch 44/100\n",
      "13/13 [==============================] - 3s 202ms/step - loss: 0.0251 - accuracy: 0.9915\n",
      "\n",
      "Epoch 00044: accuracy did not improve from 0.99447\n",
      "Epoch 45/100\n",
      "13/13 [==============================] - 3s 201ms/step - loss: 0.0297 - accuracy: 0.9893\n",
      "\n",
      "Epoch 00045: accuracy did not improve from 0.99447\n",
      "Epoch 46/100\n",
      "13/13 [==============================] - 3s 201ms/step - loss: 0.0238 - accuracy: 0.9925\n",
      "\n",
      "Epoch 00046: accuracy did not improve from 0.99447\n",
      "Epoch 47/100\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "13/13 [==============================] - 3s 201ms/step - loss: 0.0245 - accuracy: 0.9928\n",
      "\n",
      "Epoch 00047: accuracy did not improve from 0.99447\n",
      "Epoch 48/100\n",
      "13/13 [==============================] - 3s 201ms/step - loss: 0.0234 - accuracy: 0.9941\n",
      "\n",
      "Epoch 00048: accuracy did not improve from 0.99447\n",
      "Epoch 49/100\n",
      "13/13 [==============================] - 3s 201ms/step - loss: 0.0247 - accuracy: 0.9941\n",
      "\n",
      "Epoch 00049: accuracy did not improve from 0.99447\n",
      "Epoch 50/100\n",
      "13/13 [==============================] - 3s 201ms/step - loss: 0.5994 - accuracy: 0.8728\n",
      "\n",
      "Epoch 00050: accuracy did not improve from 0.99447\n",
      "Epoch 51/100\n",
      "13/13 [==============================] - 3s 201ms/step - loss: 0.3549 - accuracy: 0.8962\n",
      "\n",
      "Epoch 00051: accuracy did not improve from 0.99447\n",
      "Epoch 52/100\n",
      "13/13 [==============================] - 3s 205ms/step - loss: 0.2252 - accuracy: 0.9466\n",
      "\n",
      "Epoch 00052: accuracy did not improve from 0.99447\n",
      "Epoch 53/100\n",
      "13/13 [==============================] - 3s 217ms/step - loss: 0.1302 - accuracy: 0.9642\n",
      "\n",
      "Epoch 00053: accuracy did not improve from 0.99447\n",
      "Epoch 54/100\n",
      "13/13 [==============================] - 3s 201ms/step - loss: 0.0992 - accuracy: 0.9710\n",
      "\n",
      "Epoch 00054: accuracy did not improve from 0.99447\n",
      "Epoch 55/100\n",
      "13/13 [==============================] - 3s 201ms/step - loss: 0.0850 - accuracy: 0.9811\n",
      "\n",
      "Epoch 00055: accuracy did not improve from 0.99447\n",
      "Epoch 56/100\n",
      "13/13 [==============================] - 3s 201ms/step - loss: 0.0535 - accuracy: 0.9837\n",
      "\n",
      "Epoch 00056: accuracy did not improve from 0.99447\n",
      "Epoch 57/100\n",
      "13/13 [==============================] - 3s 201ms/step - loss: 0.0477 - accuracy: 0.9867\n",
      "\n",
      "Epoch 00057: accuracy did not improve from 0.99447\n",
      "Epoch 58/100\n",
      "13/13 [==============================] - 3s 201ms/step - loss: 0.0412 - accuracy: 0.9863\n",
      "\n",
      "Epoch 00058: accuracy did not improve from 0.99447\n",
      "Epoch 59/100\n",
      "13/13 [==============================] - 3s 201ms/step - loss: 0.0351 - accuracy: 0.9906\n",
      "\n",
      "Epoch 00059: accuracy did not improve from 0.99447\n",
      "Epoch 60/100\n",
      "13/13 [==============================] - 3s 201ms/step - loss: 0.0313 - accuracy: 0.9896\n",
      "\n",
      "Epoch 00060: accuracy did not improve from 0.99447\n",
      "Epoch 61/100\n",
      "13/13 [==============================] - 3s 201ms/step - loss: 0.0275 - accuracy: 0.9919\n",
      "\n",
      "Epoch 00061: accuracy did not improve from 0.99447\n",
      "Epoch 62/100\n",
      "13/13 [==============================] - 3s 201ms/step - loss: 0.0300 - accuracy: 0.9912\n",
      "\n",
      "Epoch 00062: accuracy did not improve from 0.99447\n",
      "Epoch 63/100\n",
      "13/13 [==============================] - 3s 200ms/step - loss: 0.0203 - accuracy: 0.9954\n",
      "\n",
      "Epoch 00063: accuracy improved from 0.99447 to 0.99545, saving model to best-model.hdf5\n",
      "Epoch 64/100\n",
      "13/13 [==============================] - 3s 201ms/step - loss: 0.0325 - accuracy: 0.9896\n",
      "\n",
      "Epoch 00064: accuracy did not improve from 0.99545\n",
      "Epoch 65/100\n",
      "13/13 [==============================] - 3s 201ms/step - loss: 0.0161 - accuracy: 0.9951\n",
      "\n",
      "Epoch 00065: accuracy did not improve from 0.99545\n",
      "Epoch 66/100\n",
      "13/13 [==============================] - 3s 201ms/step - loss: 0.0214 - accuracy: 0.9945\n",
      "\n",
      "Epoch 00066: accuracy did not improve from 0.99545\n",
      "Epoch 67/100\n",
      "13/13 [==============================] - 3s 201ms/step - loss: 0.0205 - accuracy: 0.9935\n",
      "\n",
      "Epoch 00067: accuracy did not improve from 0.99545\n",
      "Epoch 68/100\n",
      "13/13 [==============================] - 3s 202ms/step - loss: 0.0170 - accuracy: 0.9958\n",
      "\n",
      "Epoch 00068: accuracy improved from 0.99545 to 0.99577, saving model to best-model.hdf5\n",
      "Epoch 69/100\n",
      "13/13 [==============================] - 3s 202ms/step - loss: 0.0171 - accuracy: 0.9941\n",
      "\n",
      "Epoch 00069: accuracy did not improve from 0.99577\n",
      "Epoch 70/100\n",
      "13/13 [==============================] - 3s 201ms/step - loss: 0.2992 - accuracy: 0.9362\n",
      "\n",
      "Epoch 00070: accuracy did not improve from 0.99577\n",
      "Epoch 71/100\n",
      "13/13 [==============================] - 3s 200ms/step - loss: 0.1472 - accuracy: 0.9639\n",
      "\n",
      "Epoch 00071: accuracy did not improve from 0.99577\n",
      "Epoch 72/100\n",
      "13/13 [==============================] - 3s 201ms/step - loss: 0.0872 - accuracy: 0.9766\n",
      "\n",
      "Epoch 00072: accuracy did not improve from 0.99577\n",
      "Epoch 73/100\n",
      "13/13 [==============================] - 3s 201ms/step - loss: 0.0579 - accuracy: 0.9837\n",
      "\n",
      "Epoch 00073: accuracy did not improve from 0.99577\n",
      "Epoch 74/100\n",
      "13/13 [==============================] - 3s 201ms/step - loss: 0.1761 - accuracy: 0.9551\n",
      "\n",
      "Epoch 00074: accuracy did not improve from 0.99577\n",
      "Epoch 75/100\n",
      "13/13 [==============================] - 3s 200ms/step - loss: 0.0788 - accuracy: 0.9779\n",
      "\n",
      "Epoch 00075: accuracy did not improve from 0.99577\n",
      "Epoch 76/100\n",
      "13/13 [==============================] - 3s 200ms/step - loss: 0.0533 - accuracy: 0.9850\n",
      "\n",
      "Epoch 00076: accuracy did not improve from 0.99577\n",
      "Epoch 77/100\n",
      "13/13 [==============================] - 3s 213ms/step - loss: 0.0354 - accuracy: 0.9899\n",
      "\n",
      "Epoch 00077: accuracy did not improve from 0.99577\n",
      "Epoch 78/100\n",
      "13/13 [==============================] - 3s 221ms/step - loss: 0.0290 - accuracy: 0.9912\n",
      "\n",
      "Epoch 00078: accuracy did not improve from 0.99577\n",
      "Epoch 79/100\n",
      "13/13 [==============================] - 3s 205ms/step - loss: 0.0223 - accuracy: 0.9938\n",
      "\n",
      "Epoch 00079: accuracy did not improve from 0.99577\n",
      "Epoch 80/100\n",
      "13/13 [==============================] - 3s 201ms/step - loss: 0.0207 - accuracy: 0.9938\n",
      "\n",
      "Epoch 00080: accuracy did not improve from 0.99577\n",
      "Epoch 81/100\n",
      "13/13 [==============================] - 3s 201ms/step - loss: 0.0129 - accuracy: 0.9974\n",
      "\n",
      "Epoch 00081: accuracy improved from 0.99577 to 0.99740, saving model to best-model.hdf5\n",
      "Epoch 82/100\n",
      "13/13 [==============================] - 3s 201ms/step - loss: 0.0290 - accuracy: 0.9935\n",
      "\n",
      "Epoch 00082: accuracy did not improve from 0.99740\n",
      "Epoch 83/100\n",
      "13/13 [==============================] - 3s 201ms/step - loss: 0.0174 - accuracy: 0.9954\n",
      "\n",
      "Epoch 00083: accuracy did not improve from 0.99740\n",
      "Epoch 84/100\n",
      "13/13 [==============================] - 3s 201ms/step - loss: 0.0158 - accuracy: 0.9951\n",
      "\n",
      "Epoch 00084: accuracy did not improve from 0.99740\n",
      "Epoch 85/100\n",
      "13/13 [==============================] - 3s 201ms/step - loss: 0.0154 - accuracy: 0.9948\n",
      "\n",
      "Epoch 00085: accuracy did not improve from 0.99740\n",
      "Epoch 86/100\n",
      "13/13 [==============================] - 3s 201ms/step - loss: 0.0140 - accuracy: 0.9958\n",
      "\n",
      "Epoch 00086: accuracy did not improve from 0.99740\n",
      "Epoch 87/100\n",
      "13/13 [==============================] - 3s 201ms/step - loss: 0.0099 - accuracy: 0.9967\n",
      "\n",
      "Epoch 00087: accuracy did not improve from 0.99740\n",
      "Epoch 88/100\n",
      "13/13 [==============================] - 3s 201ms/step - loss: 0.0195 - accuracy: 0.9938\n",
      "\n",
      "Epoch 00088: accuracy did not improve from 0.99740\n",
      "Epoch 89/100\n",
      "13/13 [==============================] - 3s 201ms/step - loss: 0.0144 - accuracy: 0.9954\n",
      "\n",
      "Epoch 00089: accuracy did not improve from 0.99740\n",
      "Epoch 90/100\n",
      "13/13 [==============================] - 3s 209ms/step - loss: 0.0099 - accuracy: 0.9967\n",
      "\n",
      "Epoch 00090: accuracy did not improve from 0.99740\n",
      "Epoch 91/100\n",
      "13/13 [==============================] - 3s 232ms/step - loss: 0.0161 - accuracy: 0.9951\n",
      "\n",
      "Epoch 00091: accuracy did not improve from 0.99740\n",
      "Epoch 92/100\n",
      "13/13 [==============================] - 3s 201ms/step - loss: 0.0108 - accuracy: 0.9974\n",
      "\n",
      "Epoch 00092: accuracy did not improve from 0.99740\n",
      "Epoch 93/100\n",
      "13/13 [==============================] - 3s 201ms/step - loss: 0.0085 - accuracy: 0.9980\n",
      "\n",
      "Epoch 00093: accuracy improved from 0.99740 to 0.99805, saving model to best-model.hdf5\n",
      "Epoch 94/100\n",
      "13/13 [==============================] - 3s 210ms/step - loss: 0.0078 - accuracy: 0.9974\n",
      "\n",
      "Epoch 00094: accuracy did not improve from 0.99805\n",
      "Epoch 95/100\n",
      "13/13 [==============================] - 3s 207ms/step - loss: 0.0092 - accuracy: 0.9971\n",
      "\n",
      "Epoch 00095: accuracy did not improve from 0.99805\n",
      "Epoch 96/100\n",
      "13/13 [==============================] - 3s 202ms/step - loss: 0.0072 - accuracy: 0.9977\n",
      "\n",
      "Epoch 00096: accuracy did not improve from 0.99805\n",
      "Epoch 97/100\n",
      "13/13 [==============================] - 3s 201ms/step - loss: 0.0140 - accuracy: 0.9971\n",
      "\n",
      "Epoch 00097: accuracy did not improve from 0.99805\n",
      "Epoch 98/100\n",
      "13/13 [==============================] - 3s 202ms/step - loss: 0.0116 - accuracy: 0.9964\n",
      "\n",
      "Epoch 00098: accuracy did not improve from 0.99805\n",
      "Epoch 99/100\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "13/13 [==============================] - 3s 202ms/step - loss: 0.0126 - accuracy: 0.9967\n",
      "\n",
      "Epoch 00099: accuracy did not improve from 0.99805\n",
      "Epoch 100/100\n",
      "13/13 [==============================] - 3s 201ms/step - loss: 0.0118 - accuracy: 0.9961\n",
      "\n",
      "Epoch 00100: accuracy did not improve from 0.99805\n"
     ]
    }
   ],
   "source": [
    "history = model.fit(x=Xtrain, y=ytrain, batch_size=256, epochs=100, callbacks=callbacks_list)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "plt.figure(figsize=(7,7))\n",
    "plt.grid()\n",
    "plt.plot(history.history['loss'])\n",
    "#plt.plot(history.history['val_loss'])\n",
    "plt.ylabel('Loss')\n",
    "plt.xlabel('Epochs')\n",
    "plt.legend(['Training','Validation'], loc='upper right')\n",
    "plt.savefig(\"loss_curve.pdf\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "plt.figure(figsize=(5,5))\n",
    "plt.ylim(0,1.1)\n",
    "plt.grid()\n",
    "plt.plot(history.history['acc'])\n",
    "#plt.plot(history.history['val_acc'])\n",
    "plt.ylabel('Accuracy')\n",
    "plt.xlabel('Epochs')\n",
    "plt.legend(['Training','Validation'])\n",
    "plt.savefig(\"acc_curve.pdf\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Validation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "# load best weights\n",
    "model.load_weights(\"best-model.hdf5\")\n",
    "model.compile(loss='categorical_crossentropy', optimizer=adam, metrics=['accuracy'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(7175, 25, 25, 30, 1)"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Xtest = Xtest.reshape(-1, windowSize, windowSize, K, 1)\n",
    "Xtest.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(7175, 16)"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ytest = np_utils.to_categorical(ytest)\n",
    "ytest.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "             precision    recall  f1-score   support\n",
      "\n",
      "          0       1.00      1.00      1.00        32\n",
      "          1       1.00      0.99      1.00      1000\n",
      "          2       0.99      1.00      1.00       581\n",
      "          3       1.00      1.00      1.00       166\n",
      "          4       0.99      1.00      0.99       338\n",
      "          5       0.98      1.00      0.99       511\n",
      "          6       1.00      0.90      0.95        20\n",
      "          7       1.00      1.00      1.00       335\n",
      "          8       0.92      0.86      0.89        14\n",
      "          9       0.99      1.00      0.99       680\n",
      "         10       1.00      0.99      1.00      1719\n",
      "         11       1.00      0.99      0.99       415\n",
      "         12       1.00      1.00      1.00       143\n",
      "         13       1.00      1.00      1.00       886\n",
      "         14       0.99      0.98      0.99       270\n",
      "         15       1.00      0.95      0.98        65\n",
      "\n",
      "avg / total       0.99      0.99      0.99      7175\n",
      "\n"
     ]
    }
   ],
   "source": [
    "Y_pred_test = model.predict(Xtest)\n",
    "y_pred_test = np.argmax(Y_pred_test, axis=1)\n",
    "\n",
    "classification = classification_report(np.argmax(ytest, axis=1), y_pred_test)\n",
    "print(classification)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [],
   "source": [
    "def AA_andEachClassAccuracy(confusion_matrix):\n",
    "    counter = confusion_matrix.shape[0]\n",
    "    list_diag = np.diag(confusion_matrix)\n",
    "    list_raw_sum = np.sum(confusion_matrix, axis=1)\n",
    "    each_acc = np.nan_to_num(truediv(list_diag, list_raw_sum))\n",
    "    average_acc = np.mean(each_acc)\n",
    "    return each_acc, average_acc"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [],
   "source": [
    "def reports (X_test,y_test,name):\n",
    "    #start = time.time()\n",
    "    Y_pred = model.predict(X_test)\n",
    "    y_pred = np.argmax(Y_pred, axis=1)\n",
    "    #end = time.time()\n",
    "    #print(end - start)\n",
    "    if name == 'IP':\n",
    "        target_names = ['Alfalfa', 'Corn-notill', 'Corn-mintill', 'Corn'\n",
    "                        ,'Grass-pasture', 'Grass-trees', 'Grass-pasture-mowed', \n",
    "                        'Hay-windrowed', 'Oats', 'Soybean-notill', 'Soybean-mintill',\n",
    "                        'Soybean-clean', 'Wheat', 'Woods', 'Buildings-Grass-Trees-Drives',\n",
    "                        'Stone-Steel-Towers']\n",
    "    elif name == 'SA':\n",
    "        target_names = ['Brocoli_green_weeds_1','Brocoli_green_weeds_2','Fallow','Fallow_rough_plow','Fallow_smooth',\n",
    "                        'Stubble','Celery','Grapes_untrained','Soil_vinyard_develop','Corn_senesced_green_weeds',\n",
    "                        'Lettuce_romaine_4wk','Lettuce_romaine_5wk','Lettuce_romaine_6wk','Lettuce_romaine_7wk',\n",
    "                        'Vinyard_untrained','Vinyard_vertical_trellis']\n",
    "    elif name == 'PU':\n",
    "        target_names = ['Asphalt','Meadows','Gravel','Trees', 'Painted metal sheets','Bare Soil','Bitumen',\n",
    "                        'Self-Blocking Bricks','Shadows']\n",
    "    \n",
    "    classification = classification_report(np.argmax(y_test, axis=1), y_pred, target_names=target_names)\n",
    "    oa = accuracy_score(np.argmax(y_test, axis=1), y_pred)\n",
    "    confusion = confusion_matrix(np.argmax(y_test, axis=1), y_pred)\n",
    "    each_acc, aa = AA_andEachClassAccuracy(confusion)\n",
    "    kappa = cohen_kappa_score(np.argmax(y_test, axis=1), y_pred)\n",
    "    score = model.evaluate(X_test, y_test, batch_size=32)\n",
    "    Test_Loss =  score[0]*100\n",
    "    Test_accuracy = score[1]*100\n",
    "    \n",
    "    return classification, confusion, Test_Loss, Test_accuracy, oa*100, each_acc*100, aa*100, kappa*100"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "225/225 [==============================] - 3s 12ms/step - loss: 0.0194 - accuracy: 0.9948\n"
     ]
    }
   ],
   "source": [
    "classification, confusion, Test_loss, Test_accuracy, oa, each_acc, aa, kappa = reports(Xtest,ytest,dataset)\n",
    "classification = str(classification)\n",
    "confusion = str(confusion)\n",
    "file_name = \"classification_report.txt\"\n",
    "\n",
    "with open(file_name, 'w') as x_file:\n",
    "    x_file.write('{} Test loss (%)'.format(Test_loss))\n",
    "    x_file.write('\\n')\n",
    "    x_file.write('{} Test accuracy (%)'.format(Test_accuracy))\n",
    "    x_file.write('\\n')\n",
    "    x_file.write('\\n')\n",
    "    x_file.write('{} Kappa accuracy (%)'.format(kappa))\n",
    "    x_file.write('\\n')\n",
    "    x_file.write('{} Overall accuracy (%)'.format(oa))\n",
    "    x_file.write('\\n')\n",
    "    x_file.write('{} Average accuracy (%)'.format(aa))\n",
    "    x_file.write('\\n')\n",
    "    x_file.write('\\n')\n",
    "    x_file.write('{}'.format(classification))\n",
    "    x_file.write('\\n')\n",
    "    x_file.write('{}'.format(confusion))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [],
   "source": [
    "def Patch(data,height_index,width_index):\n",
    "    height_slice = slice(height_index, height_index+PATCH_SIZE)\n",
    "    width_slice = slice(width_index, width_index+PATCH_SIZE)\n",
    "    patch = data[height_slice, width_slice, :]\n",
    "    \n",
    "    return patch"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [],
   "source": [
    "# load the original image\n",
    "X, y = loadData(dataset)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [],
   "source": [
    "height = y.shape[0]\n",
    "width = y.shape[1]\n",
    "PATCH_SIZE = windowSize\n",
    "numComponents = K"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [],
   "source": [
    "X,pca = applyPCA(X, numComponents=numComponents)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [],
   "source": [
    "X = padWithZeros(X, PATCH_SIZE//2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [],
   "source": [
    "# calculate the predicted image\n",
    "outputs = np.zeros((height,width))\n",
    "for i in range(height):\n",
    "    for j in range(width):\n",
    "        target = int(y[i,j])\n",
    "        if target == 0 :\n",
    "            continue\n",
    "        else :\n",
    "            image_patch=Patch(X,i,j)\n",
    "            X_test_image = image_patch.reshape(1,image_patch.shape[0],image_patch.shape[1], image_patch.shape[2], 1).astype('float32')                                   \n",
    "            prediction = (model.predict(X_test_image))\n",
    "            prediction = np.argmax(prediction, axis=1)\n",
    "            outputs[i][j] = prediction+1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 504x504 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "ground_truth = spectral.imshow(classes = y,figsize =(7,7))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 504x504 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "predict_image = spectral.imshow(classes = outputs.astype(int),figsize =(7,7))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [],
   "source": [
    "spectral.save_rgb(\"predictions.jpg\", outputs.astype(int), colors=spectral.spy_colors)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "spectral.save_rgb(str(dataset)+\"_ground_truth.jpg\", y, colors=spectral.spy_colors)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
